--
-- Cambios en PRE para temas de visibilidad
--
ALTER TABLE public.pre
    ADD COLUMN orden integer;
ALTER TABLE public.pre
    ADD COLUMN color integer;
COMMENT ON COLUMN public.pre.orden
    IS 'Orden de aparicion en la pantalla de precios de artículos';
COMMENT ON COLUMN public.pre.color
    IS 'Color asociado (para usos varios, ejemplo la grilla de precios en articulos)';
UPDATE PRE SET COLOR = -16777201, ORDEN = 999;

-- 
-- Nuevos campo en ARTPROV para saber que variable puso el precio ahi
-- 

ALTER TABLE public.artprov
    ADD COLUMN idpre integer;

COMMENT ON COLUMN public.artprov.idpre
    IS 'Variable de precio del precio proveedor';

ALTER TABLE public.artprov
    ADD COLUMN codambusracc varchar;

COMMENT ON COLUMN public.artprov.codambusracc
    IS 'Codigo del usuario que modifico el precio';
    
--
-- Nuevos campos en prexart
--
    
ALTER TABLE public.prexart
    ADD COLUMN origen character varying(1) COLLATE pg_catalog."default";

ALTER TABLE public.prexart
    ADD COLUMN codambusracc character varying(20) COLLATE pg_catalog."default";

COMMENT ON COLUMN public.prexart.origen
    IS 'Determina el origen para saber si vino desde la tabla pura (null) o desde un subproceso (I) (Indirecto)';

COMMENT ON COLUMN public.prexart.codambusracc
    IS 'Codigo del usuario que modifico el prexart';
    

--
-- Funcion de trigger para actualizar precio de proveedor 
--

CREATE FUNCTION public.tg_prexartm_artprov()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
AS $BODY$
DECLARE
vIdPad 			integer;
BEGIN
   IF new.idpad IS NOT NULL OR new.idcomm IS NOT NULL THEN
      IF new.idcomm IS NOT null THEN 
	     SELECT comm.idpad into vIdPad FROM public.comm WHERE id = new.idcomm; 
	  ELSE
	     vIdPad 		:= new.idpad;
	  END IF;
      IF EXISTS (SELECT * FROM public.artprov 
				 WHERE idart = new.idart and idpad = vIdPad and idpre = new.idpre) 
	  THEN
	     UPDATE public.artprov SET precio = NEW.VALOR, fechaprecio = NEW.fechainsert, codambusracc = new.codambusracc
		                     WHERE idart = new.idart and idpre = new.idpre and idpad = vIdPad;
	  ELSE 
	     INSERT INTO public.artprov (idart, idpre, idpad, precio, fechaprecio, codambusracc)
         VALUES (new.idart, new.idpre, vIdPad, new.valor, new.fechainsert, new.codambusracc);
      END IF;
   END IF;
   RETURN NEW;
END;
$BODY$;

ALTER FUNCTION public.tg_prexartm_artprov()
    OWNER TO abacouser;


--
-- Tabla de historicos de precios
--

CREATE SEQUENCE public.seq_prexartm
    INCREMENT 1
    START 1
    MINVALUE 1
    MAXVALUE 9223372036854775807
    CACHE 1;

ALTER SEQUENCE public.seq_prexartm
    OWNER TO abacouser;



CREATE TABLE public.prexartm
(
    id integer NOT NULL DEFAULT nextval('seq_prexartm'::regclass),
    idpre integer NOT NULL,
    idart integer NOT NULL,
    idcomm integer,
    idpad integer,
    descripcion character varying COLLATE pg_catalog."default",
    valoranterior numeric(16,4),
    valor numeric(16,4),
    idambdb integer,
    codambusracc character varying(20) COLLATE pg_catalog."default",
	origen varchar(1),
    fechainsert timestamp without time zone,
    fechaupdate timestamp without time zone,
    CONSTRAINT prexartm_pkey PRIMARY KEY (id),
    CONSTRAINT gestion_ai_artprexartm FOREIGN KEY (idart)
        REFERENCES public.art (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE,
    CONSTRAINT gestion_ai_preprexartm FOREIGN KEY (idpre)
        REFERENCES public.pre (id) MATCH SIMPLE
        ON UPDATE NO ACTION
        ON DELETE CASCADE
)
WITH (
    OIDS = TRUE
)
TABLESPACE pg_default;

ALTER TABLE public.prexartm
    OWNER to abacouser;

COMMENT ON TABLE public.prexartm
    IS 'Precios historicos por artículo';

COMMENT ON COLUMN public.prexartm.idpre
    IS 'Identificador de la variable de precio para la que se define el precio';

COMMENT ON COLUMN public.prexartm.idart
    IS 'Identificador del artículo para el que se define el precio';

COMMENT ON COLUMN public.prexartm.idcomm
    IS 'Identificador del comprobante que modificó el precio (puede ser null)';

COMMENT ON COLUMN public.prexartm.idpad
    IS 'Idpad asociado al precio (proveedor)';

COMMENT ON COLUMN public.prexartm.descripcion
    IS 'Descripción asociada a la modificacion del precio (puede ser null)';

COMMENT ON COLUMN public.prexartm.valoranterior
    IS 'Valor del precio';

COMMENT ON COLUMN public.prexartm.valor
    IS 'Valor del precio';

COMMENT ON COLUMN public.prexartm.idambdb
    IS 'Identificador de la instancia';

COMMENT ON COLUMN public.prexartm.codambusracc
    IS 'Usuario que modifico el precio';

COMMENT ON COLUMN public.prexartm.fechainsert
    IS 'Fecha y hora de alta del registro';

COMMENT ON COLUMN public.prexartm.fechaupdate
    IS 'Fecha y hora ultima actualizacion del registro';
	
COMMENT ON COLUMN public.prexartm.origen
    IS 'Origen de la actualizacion: P: Porcentual, M: Manual, F: desde Ficha, U: Ultima Compra, E: Proceso Especial';

-- Index: prexartm_artprexartm

-- DROP INDEX public.prexartm_artprexartm;

CREATE INDEX prexartm_artprexartm
    ON public.prexartm USING btree
    (idart ASC NULLS LAST, idpre ASC NULLS LAST)
    TABLESPACE pg_default;

-- Trigger: prexartm_ins_upd

-- DROP TRIGGER prexartm_ins_upd ON public.prexartm;

CREATE TRIGGER prexartm_ins_upd
    BEFORE INSERT OR DELETE OR UPDATE 
    ON public.prexartm
    FOR EACH ROW
    EXECUTE PROCEDURE public.tg_control_audit_instancia();

-- Trigger: prexartm_ins_upd_artprov

-- DROP TRIGGER prexartm_ins_upd_artprov ON public.prexartm;

CREATE TRIGGER prexartm_ins_upd_artprov
    AFTER INSERT
    ON public.prexartm
    FOR EACH ROW
    EXECUTE PROCEDURE public.tg_prexartm_artprov();


--
-- Funcion de trigger para actualizar prexartm desde prexart
--

CREATE OR REPLACE FUNCTION public.tg_prexart_prexartm()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
AS $BODY$
DECLARE
BEGIN
    IF NEW.Origen <> 'I' THEN
	PERFORM public.prexartm_agregar(NEW.IdArt, NEW.IdPre, NULL, NULL, 'Directo', NEW.Valor, NULL, false, NEW.Origen, NEW.CodAmbUsrAcc);
    END IF;
    RETURN NEW;
END;
$BODY$;

ALTER FUNCTION public.tg_prexart_prexartm()
    OWNER TO abacouser;
    
--    
-- Trigger de prexart para invocar a prexartm cuando se actualizan precios
--    
    
DROP TRIGGER IF EXISTS prexart_prexartm ON public.prexart;

CREATE TRIGGER prexart_prexartm
    AFTER INSERT OR UPDATE 
    ON public.prexart
    FOR EACH ROW
    EXECUTE PROCEDURE public.tg_prexart_prexartm();    
    
--
-- Cambios en funciones de trigger de ultima compra para que actualicen prexart a traves de la funcion
--

CREATE OR REPLACE FUNCTION public.tg_artm_preultcompra()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
AS $BODY$
DECLARE
vOldId ArtM.Id%TYPE;
vOldModifica Com.ModificaPrecios%TYPE;
vOldVerPreciosConIva Com.VerPreciosConIva%TYPE;
vOldFecha ComM.Fecha%TYPE;
vOldIdArt ArtM.IdArt%TYPE;
vOldPreId    Pre.Id%TYPE;
vOldPreIdMon Pre.Id%TYPE;
cMovIguales REFCURSOR;
vMId          ArtM.Id%TYPE;
vMIdComM      ArtM.IdComM%TYPE;
vMPrecio      ArtM.Precio%TYPE;
vMPrecioMon   ArtM.Precio%TYPE;
vMTipoCom  ComM.TipoCom%TYPE;
vMFecha    ComM.Fecha%TYPE;
vMModifica Com.ModificaPrecios%TYPE;
vValorReal    ArtM.Precio%TYPE;
vValorRealMon ArtM.Precio%TYPE;
vValor        PreXArt.Valor%TYPE;

vCodAmbUsrAcc 	varchar;

BEGIN
-- Se recupera informacion extra del movimiento
SELECT OLD.Id, Com.ModificaPrecios, Com.verpreciosconiva, ComM.Fecha, OLD.IdArt, 
       --case when Old.CodValMon = '$' then Com.CodPre else Com.CodPreMon end, 
       Pre.Id, PreMon.Id, Comm.userAudit   -- Cod.ComPre varia segun la moneda elegida, cod.compremon siempre es la exranjera
INTO vOldId, vOldModifica, vOldVerPreciosConIva, vOldFecha, vOldIdArt, vOldPreId, vOldPreIdMon, vCodAmbUsrAcc
FROM ComM
INNER JOIN Com ON (ComM.TipoCom = Com.Tipo)
INNER JOIN Pre ON (CASE WHEN OLD.CODVALMON = '$' THEN Com.CodPre ELSE COM.CODPREMON END = Pre.Cod AND 1 = Pre.IdPreLis)  -- Segunda condicion en el join con Pre es porque falta un campo IdPreLis en COM  (Com.IdPreLis = Pre.IdPreLis) 
LEFT  JOIN Pre PreMon ON (CASE WHEN OLD.CODVALMON = '$' THEN Com.CodPreMon ELSE COM.CODPRE END = PreMon.Cod AND 1 = PreMon.IdPreLis)  -- Segunda condicion en el join con Pre es porque falta un campo IdPreLis en COM  (Com.IdPreLis = Pre.IdPreLis) 
WHERE (ComM.Id = OLD.IdComM);

-- Old.CodPreMon    Moneda del movimiento...
-- vOldModifica y com.modificaprecios vale S y >, pero ademas: A si modifica Ambas Monedas, M si modifica ambas monedas si es mayor (cada una por separado)
--IF vOldModifica IS NOT NULL AND vOldModifica in ('S', '>','A','M') THEN
IF COALESCE(vOldModifica, '') IN ('S','>','A','M') THEN
   OPEN cMovIguales FOR -- Este cursor selecciona todos los movimientos que afectaron el mismo precio que el movimiento actual
       SELECT ArtM.Id, ArtM.IdComM, -- ArtM.Precio, 
              CASE WHEN vOldVerPreciosConIva = 'S' THEN 
                CASE WHEN artm.CODVALMON = '$' THEN artm.PrecioCIva 
                     ELSE artm.PRECIOMONEDA END 
              ELSE
                CASE WHEN artm.CODVALMON = '$' THEN artm.Precio
                     ELSE artm.PRECIOMONEDA END 
              END,
              ComM.TipoCom, ComM.Fecha, Com.ModificaPrecios,
              CASE WHEN vOldVerPreciosConIva = 'S' THEN artm.PRECIOMONEDA * ARTM.PRECIOCIVA / ARTM.PRECIO 
                   ELSE CASE WHEN old.codvalmon = '$' THEN artm.PrecioMoneda 
                             ELSE artm.Precio END 
              END --  PrecioMon
        FROM ArtM
        INNER JOIN ComM ON (ArtM.IdComM = ComM.Id)
        INNER JOIN Com  ON (ComM.TipoCom = Com.Tipo)
        INNER JOIN Pre  ON (CASE WHEN ArtM.CODVALMON = '$' THEN Com.CodPre ELSE COM.CODPREMON END = Pre.Cod) AND (1 = Pre.IdPreLis) -- Segunda condicion es porque falta un campo IdPreLis en COM  (Com.IdPreLis = Pre.IdPreLis) 
        WHERE (ArtM.IdArt = OLD.IdArt) AND 
              (Com.ModificaPrecios IN ('S','>','A','M')) AND (Pre.Id = vOldPreId) AND
              (artm.preciolista is null or Artm.PrecioLista <> -1) 
        ORDER BY ComM.Fecha DESC, ArtM.Id DESC;
         
-- El fetch que sigue tomara el ultimo movimiento (x fecha desc) de ese articulo para las condiciones dadas, 
-- que puede o no ser el que se esta cargando ahora.
        FETCH cMovIguales INTO vMId, vMIdComM, vMPrecio, vMTipoCom, vMFecha, vMModifica, vMPrecioMon;
        vValorReal    := vMPrecio;
        vValorRealMon := vMPrecioMon;

        WHILE (vMModifica = '>') LOOP
           FETCH cMovIguales INTO vMId, vMIdComM, vMPrecio, vMTipoCom, vMFecha, vMModifica, vMPrecioMon;
           EXIT WHEN (NOT FOUND);
           IF (vMPrecio > vValorReal) THEN
              vValorReal := vMPrecio;
           END IF;
           IF (vMPrecioMon > vValorRealMon) THEN
              vValorRealMon := vMPrecioMon;
           END IF;
        END LOOP;
   CLOSE cMovIguales;

   IF (vValorReal IS NOT NULL) THEN -- Solo modifica el precio si encuentra algun movimiento que lo modifica
      IF vOldModifica IN ('>', 'M') THEN
         SELECT COALESCE(Valor, 0.00) INTO vValor FROM prexart WHERE idart = vOldIdart AND IdPre = vOldPreId;
         IF vValorReal > vValor THEN
			PERFORM public.prexartm_agregar(vOldIdart, vOldPreId,  NEW.IdComm, NULL, NULL, vValor, NULL, true, 'U', vCodAmbUsrAcc);
         END IF;
      ELSE
         IF vOldModifica IN ('S', 'A') AND (OLD.idcomm = vMIdComm) THEN
			PERFORM public.prexartm_agregar(vOldIdart, vOldPreId,  vMIdComm, NULL, NULL, vValor, NULL, true, 'U', vCodAmbUsrAcc);
         END IF;   
      END IF;
      
-- Si modificaba ambas monedas, ahora va la moneda extranjera (que puede ser la misma u otra)
      IF vOldModifica = 'M' then
         SELECT COALESCE(Valor, 0.00) INTO vValor FROM prexart WHERE idart = vOldIdart AND IdPre = vOldPreIdMon;
         IF vValorRealMon > vValor THEN 
			PERFORM public.prexartm_agregar(vOldIdart, vOldPreIdMon,  vMIdComm, NULL, NULL, vValorRealMon, NULL, true, 'U', vCodAmbUsrAcc);
         END IF;
      ELSE
         IF (vOldModifica = 'A')  AND (OLD.idcomm = vMIdComm) THEN
			PERFORM public.prexartm_agregar(vOldIdart, vOldPreIdMon,  vMIdComm, NULL, NULL, vValorRealMon, NULL, true, 'U', vCodAmbUsrAcc);
         END IF;   
      END IF;
/*  Antes lo borraba. Ahora no porque elimina precios que habian sido cargados a mano.
    ELSE
      DELETE FROM PreXArt WHERE (IdPre = vOldPreId)    AND (IdArt = vOldIdArt);
      DELETE FROM PreXArt WHERE (IdPre = vOldPreIdMon) AND (IdArt = vOldIdArt);
*/
   END IF;
END IF;
RETURN NEW;
END;
$BODY$;

ALTER FUNCTION public.tg_artm_preultcompra()
    OWNER TO abacouser;

-- ------------------------------

CREATE OR REPLACE FUNCTION public.tg_artm_ins_preultcompra()
    RETURNS trigger
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE 
AS $BODY$
DECLARE
vModificaPrecios Com.ModificaPrecios%TYPE;
vverpreciosconiva  Com.verpreciosconiva%TYPE;
vPreId    Pre.Id%TYPE;
vPreIdMon Pre.Id%TYPE;
vTipoCom Com.Tipo%TYPE;
vFecha Comm.Fecha%TYPE;
vHayPosteriores boolean;
vCantPre INTEGER;
vCodAmbUsrAcc   varchar(20);
vPrecioNuevo    artm.precio%type; 
vPrecioNuevoMon artm.precio%type;
BEGIN

IF (New.PrecioLista is null) OR (New.PrecioLista <> -1) then
   SELECT Com.ModificaPrecios, Pre.Id, com.tipo, comm.fecha, PreMon.Id, comm.userAudit
   INTO vModificaPrecios,   vPreId,  vTipoCom, vFecha, vPreIdMon, vCodAmbUsrAcc
   FROM public.ComM
   INNER JOIN public.Com ON (ComM.TipoCom = Com.Tipo)
   INNER JOIN public.Pre ON (CASE WHEN NEW.CODVALMON = '$' THEN Com.CodPre ELSE COM.CODPREMON END = Pre.Cod and 1 = Pre.IdPreLis)
   LEFT JOIN  public.Pre PreMon ON (CASE WHEN NEW.CODVALMON <> '$' THEN Com.CodPreMon ELSE COM.CodPre END = PreMon.Cod AND 1 = PreMon.IdPreLis) -- Segunda condicion es porque falta un campo IdPreLis en COM  (Com.IdPreLis = Pre.IdPreLis) 
   WHERE (ComM.Id = NEW.IdComM);
   IF vModificaPrecios is not null and vModificaPrecios <> 'N' then
      select verpreciosconiva into vverpreciosconiva from com, comm where comm.id = new.idcomm and com.tipo = comm.tipocom; 
      vPrecioNuevo = new.precio;
      vPrecioNuevoMon = case when new.codvalmon <> '$' then new.preciomoneda else new.precio end;   
      if vverpreciosconiva = 'S' then
         vPrecioNuevo    = new.preciociva;   
		 if (new.codvalmon <> '$') then 
		    vPrecioNuevoMon = case when new.preciomonedaciva is null then new.preciomoneda * new.preciociva / new.precio else new.preciomonedaciva end; 
		 else 
			vPrecioNuevoMon = case when new.preciomonedaciva is null then new.preciociva else new.preciomonedaciva end;   
		 end if;

      end if;

	IF (vModificaPrecios = 'S') or (vModificaPrecios = 'A') THEN
--    Lo modifica solo si no existe un movimiento similar con fecha mayor !!!!!!
		Select (Exists (Select * from artm, comm, com, pre  
						where comm.fecha > vFecha and artm.idart = New.idart and Comm.TipoCom = Com.Tipo 
						and artm.idcomm = comm.id and com.ModificaPrecios in ('S','>') 
						and (CASE WHEN ARTM.CODVALMON = '$' THEN Com.CodPre ELSE COM.CODPREMON END = Pre.Cod) and pre.id = vPreId)) 
		into vHayPosteriores;   

		IF not(vHayPosteriores) then
			PERFORM public.prexartm_agregar(NEW.IdArt, vPreId,  NEW.IdComm, NULL, NULL, 
											CASE WHEN NEW.CODVALMON = '$' THEN vPrecioNuevo ELSE vPrecioNuevoMon END,
											null, true, 'U', vCodAmbUsrAcc);
			IF vModificaPrecios = 'A' then
				PERFORM public.prexartm_agregar(NEW.IdArt, vPreIdMon,  NEW.IdComm, NULL, NULL, vPrecioNuevoMon, null, true, 'U', vCodAmbUsrAcc);
			END IF;
		END IF;
	ELSE
        IF (vModificaPrecios = '>') THEN  
            PERFORM public.prexartm_agregar(NEW.IdArt, vPreId,  NEW.IdComm, NULL, NULL, 
    	  	       CASE WHEN NEW.CODVALMON = '$' THEN vPrecioNuevo ELSE vPrecioNuevoMon END,
				   '>', true, 'U', vCodAmbUsrAcc);
	        IF (vModificaPrecios = 'M') THEN  
    	        PERFORM public.prexartm_agregar(NEW.IdArt, vPreIdMon,  NEW.IdComm, NULL, NULL, vPrecioNuevoMon, '>', true, 'U', vCodAmbUsrAcc);
		    END IF;
        END IF;
	END IF; -- (vModificaPrecios = 'S') or (vModificaPrecios = 'A')

    END IF; -- vModificaPrecios is not null and <> 'N'

END IF; --  GENERAL

RETURN NEW;

END;
$BODY$;

ALTER FUNCTION public.tg_artm_ins_preultcompra()
    OWNER TO abacouser;

COMMENT ON FUNCTION public.tg_artm_ins_preultcompra()
    IS 'Cuerpo del trigger de artm que actualiza una variable de precio de un articulo segun si el comprobante modifica precio o no.';

--
-- Funcion de actualizacion de la tabla prexartm
--

CREATE OR REPLACE FUNCTION public.prexartm_agregar(
	pidart integer,
	pidpre integer,
	pidcomm integer,
	pidpad integer,
	pdescripcion character varying,
	pvalor numeric,
	pcondicion character varying,
	pactualizoprexart boolean,
	pOrigen varchar(1),
	pcodambusracc character varying)
    RETURNS boolean
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE
AS $BODY$
DECLARE
BEGIN
  IF not (pOrigen IN ('P','M','F','I','E')) THEN
     raise exception 'Origen de actualizacion desconocido';
  END IF;
  
  IF pActualizoPreXArt THEN 
	  IF NOT EXISTS (SELECT * FROM prexart WHERE idpre = pIdPre and idart = pIdArt) THEN 
		 INSERT INTO public.prexart (IdPre, IdArt, Valor, Origen, CodAmbUsrAcc) VALUES (pIdPre, pIdArt, pValor, 'I', pCodAmbUsrAcc);
	  ELSE
		 UPDATE public.prexart SET valor = pValor, origen = 'I', CodAmbUsrAcc = pCodAmbUsrAcc
		 WHERE idPre = pIdPre and idArt = pIdArt and (pCondicion is null or (pCondicion = '>' and pValor > valor));
	  END IF;
  END IF;											   
  IF EXISTS (SELECT * FROM ambcfg WHERE position('PreciosHistoricos' IN ini) > 0) THEN
     INSERT INTO public.prexartm (idart, idpre, idcomm, idpad, descripcion, valor, origen, CodAmbUsrAcc) VALUES
	                             (pIdArt, pIdPre, pIdComm, pIdPad, pDescripcion, pValor, pOrigen, pCodAmbUsrAcc);
  
  END IF;
  RETURN true;
END;
$BODY$;

ALTER FUNCTION public.prexartm_agregar(integer, integer, integer, integer, character varying, numeric, character varying, boolean, 
									   character varying,character varying)
    OWNER TO abacouser;
    
    
    
---
SELECT aaVersion('504.00','503.00');
---



